package org.xenon.vote.model.pojo.vo;

import org.xenon.vote.exception.BallotStoppedException;
import org.xenon.vote.model.pojo.po.Choice;
import org.xenon.vote.model.pojo.po.Judge;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 一个正在进行中的投票的计分板
 */
public class Board {
    /**
     * 第几轮投票
     */
    private final int turn;

    /**
     * 当前总投票数
     */
    private int count;

    /**
     * 选出的选项数
     */
    private final int limit;

    /**
     * 投票选项的ID和选项, 方便查找
     */
    private final HashMap<Integer, Choice> regedit;

    /**
     * 所有的选项以及所得票数
     */
    private final HashMap<Choice, Integer> choices;

    /**
     * 裁判投票情况
     */
    private final HashMap<Judge, List<Integer>> status;

    /**
     * 应该出席的裁判
     */
    private final HashMap<String, Judge> shouldPresent;

    /**
     * 已经出席的裁判
     */
    private final List<Judge> presented;

    private int option; //裁判最多能投多少票

    /**
     *  @param regedit 选项和他的ID
     * @param shouldPresent 应该出席的所有评委
     */
    public Board(HashMap<Integer, Choice> regedit,
                 HashMap<String, Judge> shouldPresent,
                 int turn, int limit, int option) {
        this.regedit = regedit;
        this.option = option;
        this.choices = new HashMap<>();
        for (Choice c : this.regedit.values())
            this.choices.put(c, 0);
        this.status = new HashMap<>();
        for (Judge j : shouldPresent.values())
            this.status.put(j, new ArrayList<>());
        this.shouldPresent = shouldPresent;
        this.presented = new ArrayList<>();
        this.turn = turn;
        this.count = 0;
        this.limit = limit;
    }

    public Judge getJudge(String name){
        return shouldPresent.get(name);
    }

    /**
     * 检查投票是否完成
     */
    public boolean check(){
        for (Judge j : presented)
            if(status.get(j).size() < limit)
                return false;
        return true;
    }

    public int getOption() {
        return option;
    }

    public int getTurn() {
        return turn;
    }

    public int getCount() {
        return count;
    }

    public int getLimit() {
        return limit;
    }

    /**
     * 给选项投票
     * @param name 裁判名字
     * @param id 选项ID
     * @return 是否成功
     */
    public boolean vote(String name, int id){
        Judge judge = shouldPresent.get(name);
        if (judge == null) return false;
        if (status.get(judge).contains(id)|| status.get(judge).size()>= option || !regedit.containsKey(id)) return false;
        status.get(judge).add(id);
        choices.put(regedit.get(id), choices.get(regedit.get(id)) + 1);
        count++;
        return true;
    }

    /**
     * 裁判加入投票
     * @param judge 裁判
     * @return 是否成功
     */
    public boolean attend(Judge judge){
        if((judge = shouldPresent.get(judge.getName())) == null) return false;
        if (presented.contains(judge))
            return true;
        presented.add(judge);
        return true;
    }

    /**
     * 裁判退出投票
     * @param name 裁判名字
     * @return 是否成功
     */
    public boolean drop(String name){
        Judge judge;
        if((judge = shouldPresent.get(name)) == null) return true;
        presented.remove(judge);
        check();
        return true;
    }

    /**
     *
     * @return 获取所有选项
     * @throws BallotStoppedException 投票已经结束或者未准备好
     */
    public HashMap<Integer, Choice> getRegedit() throws BallotStoppedException {
        throw new BallotStoppedException("投票已经结束");
    }

    /**
     *
     * @return 所有的选项以及所得票数
     */
    public HashMap<Choice, Integer> getChoices() {
        return choices;
    }

    /**
     *
     * @return 裁判投票情况
     */
    public List<Integer> getStatus(String name, String owner) {
        List<Integer> list = new ArrayList<>();
        for (Judge j:status.keySet())
            if(j.getName().equals(name)&&j.getOwner().equals(owner)) list.addAll(status.get(j));
        return list;
    }

    /**
     *
     * @return 应该出席的评委
     */
    public HashMap<String, Judge> getShouldPresent() {
        return shouldPresent;
    }

    /**
     *
     * @return 已经出席的评委
     */
    public List<Judge> getPresented() {
        return presented;
    }
}
